<?php
/**
 * 微信公众号相关接口类
 * Created by PhpStorm.
 * User: phperstar
 * Date: 2019/10/26
 * Time: 11:44 AM
 */
namespace Util\WeiXin;

use Mall\Framework\Core\ResultWrapper;
use Mall\Framework\Core\ErrorCode;
use Mall\Framework\Factory;

class Offiaccount
{
    /**
     * 公众号 appId
     * @var string $appid
     */
    private $appid;
    /**
     * 公众号 appSecret
     * @var string $appSecret
     */
    private $appSecret;

    /**
     * 促销卡
     * @var string $cardid
     */
    private $cardid;

    // access_token 公众号的全局唯一接口调用凭据
    private $access_token = 'accessToken';

    // jsapi_ticket 公众号用于调用微信JS接口的临时票据
    private $jsapi_ticket = 'jsapiTicket';

    /**
     * 微信公众号接口主域名
     * @var string $apiUrl
     */
    private $apiUrl = 'https://api.weixin.qq.com/cgi-bin/';

    // 小程序
    private $wxUrl = 'https://api.weixin.qq.com/wxa/';

    /**
     * 基础接口地址
     * @var string $baseUrl
     */
    private $baseUrl = 'https://api.weixin.qq.com/sns/';

    /**
     * Offiaccount constructor.
     * @param string $appid
     * @param string $appsecret
     * @param string $cardid
     */
    public function __construct($appid='', $appsecret='', $cardid='')
    {
        $this->appid = $appid;
        $this->appSecret = $appsecret;
        $this->cardid = $cardid;
    }


    /**
     * 获取基础access_token
     * 官方文档对应地址: https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html
     * @return ResultWrapper
     */
    public function token()
    {
        $access_token =  Factory::cache('default')->get($this->access_token.':'.$this->appid);
        if(!empty($access_token)){
            return ResultWrapper::success($access_token);
        }

        $apiUrl = $this->apiUrl.'token?grant_type=client_credential&appid='.$this->appid.'&secret='.$this->appSecret;
        $reponse =  request($apiUrl);

        if($reponse['httpcode'] != 200){
            return ResultWrapper::fail('请求外部系统接口报错', ErrorCode::$apiNotResult);
        }else{
            $reponseData = json_decode($reponse['content'], true);
            if( isset($reponseData['errcode']) ){
                return ResultWrapper::fail($reponseData['errmsg'], $reponseData['errcode']);
            }

            Factory::cache('default')->set($this->access_token.':'.$this->appid, $reponseData['access_token'], 7000);
            return ResultWrapper::success($reponseData['access_token']);
        }
    }

    /**
     * 文本安全内容检测
     */
    public function msg_sec_check($content)
    {
        $result = self::token();
        if (!$result->isSuccess()) {
            return ResultWrapper::fail($result->getData(), $result->getErrorCode());
        }
        $access_token = $result->getData();

        $postData = [
            'content' => $content,
        ];

        $url = $this->wxUrl . 'msg_sec_check?access_token=' . $access_token;
        $response = request($url, json_encode($postData, JSON_UNESCAPED_UNICODE), 10);
        $result = self::commonResponse($response);
        if (!$result->isSuccess()) {
            return ResultWrapper::fail('内容含有违法违规内容', $result->getErrorCode());
        }

        return ResultWrapper::success($result->getData());
    }

    /**
     * 图片安全内容检测
     */
    public function img_sec_check($media)
    {
        $result = self::token();
        if (!$result->isSuccess()) {
            return ResultWrapper::fail($result->getData(), $result->getErrorCode());
        }
        $authorizer_access_token = $result->getData();

        $media = file_get_contents($media);
        if (empty($media)) {
            return ResultWrapper::fail('图片内容为空', ErrorCode::$contentNotExists);
        }
        $boundary="----".md5(date);
        $formdata = "--" . $boundary ."\r\n";
        $formdata .= "Content-Disposition: form-data; name=\"upload\"; filename=\"upload.jpg\"\r\n";
        $formdata .= "Content-type: application/octet-stream\r\n\r\n";
        $formdata .= $media."\r\n";
        $formdata .= "--" . $boundary . "\r\n"."--\r\n\r\n";

        $curl_option = [
            CURLOPT_HTTPHEADER => [
                'Content-Type: multipart/form-data; boundary='.$boundary,
                'Content-Length: '.strlen($formdata),
            ],
        ];

        $url = $this->wxUrl . 'img_sec_check?access_token=' . $authorizer_access_token;
        $response = request($url, $formdata, 10, true, $curl_option);
        $result = self::commonResponse($response);
        if (!$result->isSuccess()) {
            return ResultWrapper::fail('图片含有违法违规内容', $result->getErrorCode());
        }

        return ResultWrapper::success($result->getData());
    }

    /**
     * 获取jsapi_ticket
     */
    public function jsapiTicket($access_token)
    {
        $jsapi_ticket =  Factory::cache('default')->get($this->jsapi_ticket.':'.$this->appid);
        if(!empty($jsapi_ticket)){
            return ResultWrapper::success($jsapi_ticket);
        }

        $apiUrl = $this->apiUrl.'ticket/getticket?type=jsapi&access_token='.$access_token;
        $reponse =  request($apiUrl);

        if($reponse['httpcode'] != 200){
            return ResultWrapper::fail('请求外部系统接口报错', ErrorCode::$apiNotResult);
        }else{
            $reponseData = json_decode($reponse['content'], true);
            if( isset($reponseData['errcode']) && !empty($reponseData['errcode'])){
                return ResultWrapper::fail($reponseData['errmsg'], $reponseData['errcode']);
            }

            Factory::cache('default')->set($this->jsapi_ticket.':'.$this->appid, $reponseData['ticket'], 7000);
            return ResultWrapper::success($reponseData['ticket']);
        }
    }




    /**
     * 获取getJsSdkConfig
     * 官方文档地址: https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#62
     */
    public function getJsSdkConfig()
    {
        $result = self::token();
        if(!$result->isSuccess()){
            return ResultWrapper::fail($result->getData(),$result->getErrorCode());
        }
        $access_token = $result->getData();
        unset($result);

        $result = self::jsapiTicket($access_token);
        if(!$result->isSuccess()){
            return ResultWrapper::fail($result->getData(),$result->getErrorCode());
        }
        $jsapi_ticket = $result->getData();
        unset($result);

        $nonceStr = self::createNonceStr();
        $timestamp = time();

        // 注意 URL 一定要动态获取，不能 hardcode.
        $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
        //$url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
        $url = isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:'';

        $string = "jsapi_ticket={$jsapi_ticket}&noncestr=$nonceStr&timestamp=$timestamp&url=$url";
        $signature = sha1($string);

        $signPackage = [
            "appId"     => $this->appid,
            "nonceStr"  => $nonceStr,
            "timestamp" => $timestamp,
            "url"       => $url,
            "signature" => $signature,
            "rawString" => $string,
            "accessToken" => $access_token
        ];

        return ResultWrapper::success($signPackage);
    }

    /**
     * 获取网页access_token
     * 官方文档对应地址: https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#1
     * @return ResultWrapper
     */
    public function access_token($code)
    {
        $apiUrl = $this->baseUrl.'oauth2/access_token?appid='.$this->appid.'&secret='.$this->appSecret.'&code='.$code.'&grant_type=authorization_code';
        $reponse =  request($apiUrl);

        if($reponse['httpcode'] != 200){
            return ResultWrapper::fail('请求外部系统接口报错', ErrorCode::$apiNotResult);
        }else{
            $reponseData = json_decode($reponse['content'], true);
            if( isset($reponseData['errcode']) ){
                return ResultWrapper::fail($reponseData['errmsg'], $reponseData['errcode']);
            }
            return ResultWrapper::success($reponseData);
        }
    }

    // 创建随机字符函数
    private function createNonceStr($length = 16)
    {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    /**
     * 用于获取用户个人信息
     */
    public function userinfo($access_token, $openid)
    {
        $apiUrl = $this->baseUrl.'userinfo?access_token='.$access_token.'&openid='.$openid;
        $reponse =  request($apiUrl);

        if($reponse['httpcode'] != 200){
            return ResultWrapper::fail('请求外部系统接口报错', ErrorCode::$apiNotResult);
        }else{
            $reponseData = json_decode($reponse['content'], true);
            if( isset($reponseData['errcode']) ){
                return ResultWrapper::fail($reponseData['errmsg'], $reponseData['errcode']);
            }
            return ResultWrapper::success($reponseData);
        }
    }

    /**
     * 获取用户基本信息(UnionID机制)
     * 官网地址: https://developers.weixin.qq.com/doc/offiaccount/User_Management/Get_users_basic_information_UnionID.html#UinonId
     */
    public function info($access_token, $openid)
    {
        $apiUrl = $this->apiUrl.'user/info?access_token='.$access_token.'&openid='.$openid.'&lang=zh_CN';
        $reponse =  request($apiUrl);

        if($reponse['httpcode'] != 200){
            return ResultWrapper::fail('请求外部系统接口报错', ErrorCode::$apiNotResult);
        }else{
            $reponseData = json_decode($reponse['content'], true);
            if( isset($reponseData['errcode']) ){
                return ResultWrapper::fail($reponseData['errmsg'], $reponseData['errcode']);
            }
            return ResultWrapper::success($reponseData);
        }
    }

    /**
     * 公共处理返回结果函数
     */
    public function commonResponse($response, $isBinary = false)
    {
        if ($response['httpcode'] != 200) {
            return ResultWrapper::fail('请求外部系统接口报错', ErrorCode::$apiNotResult);
        }

        if (!is_object($response['content']) && $isBinary) {
            return ResultWrapper::success($response['content']);
        }
        $responseData = json_decode($response['content'], true);
        if (isset($responseData['errcode']) && $responseData['errcode'] != 0) {
            return ResultWrapper::fail($responseData['errmsg'], $responseData['errcode']);
        }
        return ResultWrapper::success($responseData);
    }

}